package api.cie.rss.utils;

import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.StringReader;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;

import api.cie.rss.common.Article;
import api.cie.rss.common.RSS;

/**
 * The class used for parsing XML files
 * @author STL-API
 *
 */
public class ParserTools {

	public static final String TAG_RSS = "rss";
	public static final String TAG_CHANNEL = "channel";
	public static final String TAG_ITEM = "item";
	public static final String TAG_TITLE = "title";
	public static final String TAG_LINK = "link";
	public static final String TAG_DESCRIPTION = "description";
	public static final String TAG_PUBDATE = "pubDate";
	public static final String XML_HEADER = "<?xml version='1.0' encoding='iso-8859-1'?>\n";
	public static final String XML_RSS = "<rss version='2.0' xmlns:rdf='http://www.w3.org/1999/02/22-rdf-syntax-ns#'>\n";
	
	public static String toXML(List<Article> articles) {
		String xmlStr = XML_HEADER + XML_RSS;
		xmlStr += "<" + TAG_CHANNEL + ">\n";
		for(Article article:articles) {
			xmlStr += "<" + TAG_ITEM + ">\n";
			xmlStr += "<" + TAG_TITLE +  ">" + article.getTitle() + 
						"</" + TAG_TITLE +  ">\n";
			xmlStr += "<" + TAG_DESCRIPTION +  ">" + article.getDescription() + 
						"</" + TAG_DESCRIPTION +  ">\n";
			xmlStr += "<" + TAG_LINK +  ">" + Utils.processURL(article.getUrl()) + 
						"</" + TAG_LINK +  ">\n";
			xmlStr += "<" + TAG_PUBDATE +  ">" + article.getPublishingDate() + 
						"</" + TAG_PUBDATE +  ">\n";
			xmlStr += "</" + TAG_ITEM + ">\n";
		}
		xmlStr += "</" + TAG_CHANNEL + ">\n";
		xmlStr += "</" + TAG_RSS + ">\n";
		return xmlStr;
	}
	
	public static List<Article> getArticles(String url) {
		try {
			URL urlObj = new URL(url);
			URLConnection connection = urlObj.openConnection();
			InputStream stream = new BufferedInputStream(connection.getInputStream());			
			return getArticlesFromStream(stream);
		} catch (Exception e) {	
			return null;
		}
	}
	
	public static List<Article> getArticlesFromStream(InputStream stream) {
		try { 
			final DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
			final DocumentBuilder db = dbf.newDocumentBuilder();
			final Document dom = db.parse(stream);
			Node channelNode = dom.getElementsByTagName(TAG_CHANNEL).item(0);
			List<Article> result = parseArticles(channelNode);
			return result;
		} catch (Exception e) {
			return null;
		}
	}

	private static List<Article> parseArticles(Node channelNode) {
		List<Article> articles = new ArrayList<Article>();
		List<Node> articleNodes = searchChildren(channelNode, TAG_ITEM);
		for(Node n:articleNodes) {
			articles.add(parseNode(n));
		}
		return articles;
	}
	
	private static Article parseNode(Node n) {
		Article article = new Article();
		NodeList children = n.getChildNodes();
		for(int i=0; i<children.getLength(); i++) {
			Node child = children.item(i);
			if(child == null || child.getNodeType() != Node.ELEMENT_NODE) continue;
			String value = child.getTextContent();
			if(child.getNodeName().equals(TAG_TITLE)) {
				article.setTitle(value);
			} else if(child.getNodeName().equals(TAG_LINK)) {
				article.setUrl(value);
			} else if(child.getNodeName().equals(TAG_DESCRIPTION)) {
				article.setDescription(value);
			} else if(child.getNodeName().endsWith(TAG_PUBDATE)) {
				try {					
					article.setPublishingDate(Utils.dateFromString(value));
				} catch (Exception e) {
					article.setPublishingDate(new Date());
				}				
			}
		}
		return article;
	}

	/**
	 * Get 5 premier items
	 * @param n
	 * @param name
	 * @return
	 */
	private static List<Node> searchChildren(Node n, String name) {
		List<Node> result = new ArrayList<Node>();
		NodeList children = n.getChildNodes();
		for(int i=0; i<children.getLength(); i++) {
			Node child = children.item(i);
			if(child.getNodeName().equals(name)) {
				result.add(child);
			}
			if(result.size() >= 5) break;
		}
		return result;
	}	
	
    private static String getAttributeValue(Node n, String attribute) {
    	if (n.getAttributes().getNamedItem(attribute) == null)
    		return "";
        return n.getAttributes().getNamedItem(attribute).getNodeValue();
    }
    
    private static List<Node> searchNodeWithAttribute(NodeList list, String attribute, String value) {
    	List<Node> result = new ArrayList<Node>();
    	for(int i=0; i<list.getLength(); i++) {
    		Node n = list.item(i);
    		if(getAttributeValue(n, attribute).equals(value)) result.add(n);
    	}
    	return result;
    }    
	
	public static String downloadPage(String url) {
    	try {
			URL urlPage = new URL(url);
			HttpURLConnection connection = (HttpURLConnection) urlPage.openConnection();
			InputStream inputStream = connection.getInputStream();
			BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream,"ISO-8859-1"));
			
			StringBuffer stringBuffer = new StringBuffer();
			String line;
			
			while((line = bufferedReader.readLine()) != null) {
				stringBuffer.append(line);
			}
						
			connection.disconnect();
			bufferedReader.close();
			inputStream.close();
			
			return stringBuffer.toString();
			
		} catch (MalformedURLException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return "";
    }
	
	private static String getHead(String url){
		String file = downloadPage(url);
		String head = file.split("<head>")[1].split("</head>")[0];
		head = getLinkTag(head, "link");
		return "<?xml version='1.0' encoding='ISO-8859-1'?> <head>" + head + "</head>";
		
	}
	
	private static String getLinkTag(String originalStr, String tag) {
		String startTag = "<" + tag;
		String endTag = "</" + tag + ">";
		String link = "";
		String result = originalStr;
		while (true) {
			int pos = result.indexOf(startTag);			
			if (pos < 0) break;
			int posNext = result.indexOf(startTag, pos + 1);
			int posEnd = -1;
			int tmp = result.indexOf(endTag, pos); 
			posEnd = tmp < 0 ? -1 : (tmp + endTag.length());
			if ((posNext > 0 && posEnd > posNext) || posEnd == -1) {
				posEnd = result.indexOf("/>", pos) + 2;
			}
			link += result.substring(pos, posEnd); 
			result = result.substring(0, pos) + result.substring(posEnd);
		}		
		return link;
	}

	
	public static List<RSS> getRSS(String url){
		List<RSS> listRSS = new ArrayList<RSS>();
		try {
			String file = getHead(url);
			final DocumentBuilderFactory dbfs = DocumentBuilderFactory.newInstance();
			final DocumentBuilder dbs = dbfs.newDocumentBuilder();
			final Document doms = dbs.parse(new InputSource(new StringReader(file))); 
			
			NodeList list = doms.getElementsByTagName("link");
			
			List<Node> listNode = searchNodeWithAttribute(list, "type", "application/rss+xml");
			for(int i=0; i<listNode.size(); i++ ){
				RSS rss = new RSS();
				rss.setActive(true);
				rss.setTitle(getAttributeValue(listNode.get(i), "title"));
				rss.setUrl(getAttributeValue(listNode.get(i), "href"));
				listRSS.add(rss);
			}
			
		} catch (Exception e) {			
			
		}
		
		return listRSS;
	}
	
}
